home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / tags18.zip / ASMTAG.C < prev    next >
C/C++ Source or Header  |  1991-11-18  |  20KB  |  559 lines

  1. /*
  2.  EPSHeader
  3.  
  4.    File: asmtag.c
  5.    Author: J. Kercheval
  6.    Created: Sun, 07/14/1991  17:25:26
  7. */
  8. /*
  9.  EPSRevision History
  10.  
  11.    J. Kercheval  Sun, 07/14/1991  20:25:59  creation
  12.    J. Kercheval  Mon, 07/15/1991  22:47:30  finish finite state machine parser
  13.    J. Kercheval  Wed, 07/17/1991  21:35:43  add IsMember() and get_token()
  14.    J. Kercheval  Thu, 07/18/1991  19:57:34  add flags checking
  15.    J. Kercheval  Sun, 07/21/1991  15:58:56  add comment block support
  16.    J. Kercheval  Sat, 07/27/1991  21:16:53  remove public post process support
  17.    J. Kercheval  Sat, 07/27/1991  22:50:49  performance considerations (+10%)
  18.    J. Kercheval  Sat, 08/10/1991  17:48:28  speed up IsMember()
  19.    J. Kercheval  Sat, 08/17/1991  22:50:29  use unique function names (ASM...)
  20.    J. Kercheval  Sun, 08/25/1991  23:52:51  fix bug in ASMSymbolWanted()
  21.    J. Kercheval  Thu, 10/03/1991  12:27:37  fix logic outputting local labels
  22. */
  23.  
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. #include "asmtag.h"
  28. #include "tagio.h"
  29.  
  30.  
  31. /*
  32.  * The finite state machine allows the following interesting paths
  33.  *
  34.  *    1 - Discard, Parse1, Symbol1
  35.  *    2 - Discard, Parse1, Parse2, Symbol2
  36.  *    3 - Discard, Parse1, Parse2, Define
  37.  *
  38.  * all the important cases follow one of these paths according to MASM/TASM
  39.  * syntax.  The exit state is for finish up routine calls and some paths not
  40.  * covered here are simple error paths and probably result from syntax errors
  41.  */
  42. enum state {
  43.     Discard, Parse1, Parse2, Symbol1, Symbol2, Define, Exit
  44. };
  45.  
  46. typedef enum state State;
  47.  
  48.  
  49. #define COMMENT_CHAR ';'
  50.  
  51. #define SYMBOL_SIZE 15
  52.  
  53.  
  54. /*----------------------------------------------------------------------------
  55.  *
  56.  * The symbol lists represent all the symbols we are interested in either
  57.  * obtaining or ignoring.  The order of some of these token lists is
  58.  * important for determining if ouput should be performed.  If you want to
  59.  * change these lists make sure that flag checking is altered to change the
  60.  * changed order.  The first element of each of these symbol lists is a
  61.  * string containing all the first characters within the symbol list.  This
  62.  * allows faster rejection for IsMember() which is called often.
  63.  *
  64.  ---------------------------------------------------------------------------*/
  65.  
  66. /* symbols which are not significant for this parser */
  67. char ASM_NOP_Sym[][SYMBOL_SIZE] =
  68. {
  69.     "cpbfnwo",                  /* list of starting characters of symbols
  70.                                  * below */
  71.     "c",                        /* C language declaration */
  72.     "pascal",                   /* PASCAL language declaration */
  73.     "basic",                    /* BASIC language declaration */
  74.     "fortran",                  /* FORTRAN language declaration */
  75.     "prolog",                   /* PROLOG language declaration */
  76.     "nolanguage",               /* generic language declaration */
  77.     "windows",                  /* WINDOWS exit and entry modifier */
  78.     "oddnear",                  /* overlay modifier */
  79.     "oddfar",                   /* overlay modifier */
  80.     "normal",                   /* normal procedure entry/exit code */
  81.     "\0"
  82. };
  83.  
  84. /* symbols which begin a comment block */
  85. char ASM_comment_block[][SYMBOL_SIZE] =
  86. {
  87.     "c",                        /* list of starting characters of symbols
  88.                                  * below */
  89.     "comment",                  /* begin comment block, next character is
  90.                                  * delimiter */
  91.     "\0"
  92. };
  93.  
  94.  
  95. /* create the function for determining if a character is a delimiter */
  96. #define IsDelim(c) ( _ASM_delim_table[c] )
  97.  
  98. /* the indexed table for white space character lookup */
  99. BOOLEAN _ASM_delim_table[256];
  100.  
  101. /* valid delimiters for this syntax */
  102. char ASM_delim[] = " \t;:=.,\"()<>[]*-+/";
  103.  
  104.  
  105. /* create the function for determining if a character is a whitespace */
  106. #define IsWhite(c) ( _ASM_white_table[c] )
  107.  
  108. /* the indexed table for white space character lookup */
  109. BOOLEAN _ASM_white_table[256];
  110.  
  111. /* whitespace characters */
  112. char ASM_white[] = " \t\v\f";
  113.  
  114.  
  115. /* symbols which both are delimiters and a special token, these are
  116.     special tokens only when found at the the beginning of a string of
  117.     1 or more delimiters */
  118. char ASM_delim_Sym[] = "=:";
  119.  
  120. /* symbols which fit into the Define state and represent a tagged symbol */
  121. /* state Define depends on the token ":" being at index 1 in this list */
  122. char ASM_def[][SYMBOL_SIZE] =
  123. {
  124.     ":e=cd",                    /* list of starting characters of symbols
  125.                                  * below */
  126.     ":",                        /* local labels */
  127.     "equ",                      /* equivalence */
  128.     "=",                        /* equivalence */
  129.     "catstr",                   /* concatenated and named strings */
  130.     "db",                       /* named byte data definition */
  131.     "dw",                       /* named word data definition */
  132.     "dd",                       /* named double word data definition */
  133.     "dp",                       /* named 6 byte far pointer data area
  134.                                  * definition */
  135.     "df",                       /* named 6 byte far pointer definition */
  136.     "dq",                       /* named quad word data definition */
  137.     "dt",                       /* named 10 byte data area */
  138.     "\0"
  139. };
  140.  
  141. /* symbols which fit into the Symbol state and represent a tagged symbol */
  142. char ASM_sym[][SYMBOL_SIZE] =
  143. {
  144.     "pmlsu",                    /* list of starting character of symbols
  145.                                  * below */
  146.     "proc",                     /* procedures */
  147.     "macro",                    /* macros */
  148.     "label",                    /* local labels */
  149.     "struc",                    /* structures */
  150.     "union",                    /* unions */
  151.     "\0"
  152. };
  153.  
  154.  
  155. /*----------------------------------------------------------------------------
  156.  *
  157.  * ASMParserInit() initializes the tables required by the parser The tables
  158.  * used are a simple boolean index which are true if the character
  159.  * corresponding to the index is a member of the associated table.
  160.  *
  161.  ---------------------------------------------------------------------------*/
  162.  
  163. void ASMParserInit()
  164. {
  165.     char *s;
  166.     int i;
  167.  
  168.     /* init the entire block to FALSE */
  169.     for (i = 0; i < 256; i++) {
  170.         _ASM_delim_table[i] = FALSE;
  171.         _ASM_white_table[i] = FALSE;
  172.     }
  173.  
  174.     /* set the characters in the delim set to TRUE */
  175.     for (s = ASM_delim; *s; s++) {
  176.         _ASM_delim_table[*s] = TRUE;
  177.     }
  178.  
  179.     /* NULL is also a delimiter */
  180.     _ASM_delim_table['\0'] = TRUE;
  181.  
  182.     /* set the characters in the white set to TRUE */
  183.     for (s = ASM_white; *s; s++) {
  184.         _ASM_white_table[*s] = TRUE;
  185.     }
  186. }
  187.  
  188. /*----------------------------------------------------------------------------
  189.  *
  190.  * ASMSymbolWanted() returns true if the index into the sym token list is one
  191.  * of the wanted symbols according to the flags list.  The indexes belong
  192.  * with the following symbols and flags:
  193.  *
  194.  *          Flag       Symbol   Index
  195.  *          ---------  -------  -----
  196.  *          flags->af  "proc"   1
  197.  *          flags->am  "macro"  2
  198.  *          flags->al  "label"  3
  199.  *          flags->as  "struc"  4
  200.  *          flags->au  "union"  5
  201.  *
  202.  ---------------------------------------------------------------------------*/
  203.  
  204. BOOLEAN ASMSymbolWanted(Flags * flags, int index)
  205. {
  206.     /* return true if the associated flag is true */
  207.     switch (index) {
  208.             case 1:
  209.             return flags->af;
  210.             break;
  211.         case 2:
  212.             return flags->am;
  213.             break;
  214.         case 3:
  215.             return flags->al;
  216.             break;
  217.         case 4:
  218.             return flags->as;
  219.             break;
  220.         case 5:
  221.             return flags->au;
  222.             break;
  223.         default:
  224.             return FALSE;
  225.             break;
  226.     }
  227. }
  228.  
  229.  
  230. /*----------------------------------------------------------------------------
  231.  *
  232.  * ASMIsMember() takes the token passed and check for membership in the null
  233.  * terminated array, tokenlist, and return TRUE if a member and FALSE
  234.  * otherwise, index is the index into the token list of the symbol if return
  235.  * value is TRUE
  236.  *
  237.  ---------------------------------------------------------------------------*/
  238.  
  239. BOOLEAN ASMIsMember(char token_list[][SYMBOL_SIZE], char *token, int *index)
  240. {
  241.  
  242.     /* look for dirty rejection */
  243.     if (!strchr(token_list[0], tolower(token[0])))
  244.         return FALSE;
  245.  
  246.     /* march through array until membership is determined */
  247.     for (*index = 1; *token_list[*index]; (*index)++) {
  248.  
  249.         /* return true if token found */
  250.         if (!stricmp(token, token_list[*index])) {
  251.             return TRUE;
  252.         }
  253.     }
  254.  
  255.     /* did not find it */
  256.     return FALSE;
  257. }
  258.  
  259.  
  260. /*----------------------------------------------------------------------------
  261.  *
  262.  * ASM_get_token() will obtain the next token in the line pointed to by lptr
  263.  * and in addition will return FALSE if EOL is reached or a comment character
  264.  * is the first non whitespace character found
  265.  *
  266.  ---------------------------------------------------------------------------*/
  267.  
  268. BOOLEAN ASM_get_token(char **lptr, char *token)
  269. {
  270.     char *s;                    /* start location in string */
  271.     int token_length;           /* the length of the current token */
  272.     int dummy;                  /* a temporary variable */
  273.  
  274.     /* loop until we have a valid token or end of string */
  275.     do {
  276.         /* move past whitespace */
  277.         while (IsWhite(**lptr)) {
  278.             (*lptr)++;
  279.         }
  280.  
  281.         /* return false if end of line */
  282.         if (!**lptr)
  283.             return FALSE;
  284.  
  285.         /* check if comment */
  286.         if (**lptr == COMMENT_CHAR) {
  287.             return FALSE;
  288.         }
  289.  
  290.         /* check for delimiter token */
  291.         if (strchr(ASM_delim_Sym, **lptr)) {
  292.             token[0] = **lptr;
  293.             token[1] = '\0';
  294.             (*lptr)++;
  295.         }
  296.         else {
  297.  
  298.             /* save the beginning location */
  299.             s = *lptr;
  300.  
  301.             /* move to the next delimiter in the line */
  302.             while (!IsDelim(**lptr)) {
  303.                 (*lptr)++;
  304.             }
  305.  
  306.             /* get the token */
  307.             token_length = *lptr - s;
  308.             strncpy(token, s, token_length);
  309.             token[token_length] = '\0';
  310.         }
  311.  
  312.     } while (ASMIsMember(ASM_NOP_Sym, token, &dummy));
  313.  
  314.     return TRUE;
  315. }
  316.  
  317.  
  318. /*----------------------------------------------------------------------------
  319.  *
  320.  * ASMtags() tags an input stream assuming input format of ASM 80x86 format
  321.  * in MASM/TASM syntax
  322.  *
  323.  ---------------------------------------------------------------------------*/
  324.  
  325. #define TOKEN_LINE_LENGTH 256
  326.  
  327. void ASMTags(FILE * infile, char *infname, FILE * outfile, Flags * flags)
  328. {
  329.     State state;                /* the current state of the parser */
  330.  
  331.     char line[TOKEN_LINE_LENGTH];       /* the current input line */
  332.     char cur_token[TOKEN_LINE_LENGTH];  /* the current token */
  333.     char prev_token[TOKEN_LINE_LENGTH]; /* the previous token */
  334.  
  335.     char *lptr;                 /* pointer into line for token parser */
  336.     char *prev_lptr;            /* pointer into line for previous token */
  337.  
  338.     long int line_number;       /* the current line in the file */
  339.     int line_length;            /* the length of the current line */
  340.     long int char_number;       /* the current character in the file */
  341.  
  342.     int symbol_index;           /* the index into the token list of the
  343.                                  * symbol */
  344.  
  345.     /* init the engine */
  346.     ASMParserInit();
  347.     cur_token[0] = '\0';
  348.     prev_token[0] = '\0';
  349.     state = Discard;
  350.     line_number = 0;
  351.     line_length = 0;
  352.     char_number = -1;
  353.     lptr = prev_lptr = (char *) NULL;
  354.  
  355.     for (;;) {
  356.  
  357.         switch (state) {
  358.  
  359.             case Discard:       /* current line is not valid */
  360.  
  361.                 /* if EOF then return */
  362.                 if (GetLine(infile, line, TOKEN_LINE_LENGTH)) {
  363.                     lptr = line;
  364.  
  365.                     /* increment counters */
  366.                     line_number++;
  367.  
  368.                     /* char_number increments by length of previous line */
  369.                     char_number += line_length + 1;
  370.  
  371.                     /* line length */
  372.                     line_length = strlen(line);
  373.                     state = Parse1;
  374.                 }
  375.                 else {
  376.                     state = Exit;
  377.                 }
  378.                 break;
  379.  
  380.             case Parse1:        /* parsing for first *special* token */
  381.  
  382.                 /* get the next valid token */
  383.                 if (!ASM_get_token(&lptr, cur_token)) {
  384.  
  385.                     /* if no token left or a comment as first non white space
  386.                      * char in remainder of line */
  387.                     state = Discard;
  388.                 }
  389.                 else {
  390.  
  391.                     /* move the cur_token to prev_token */
  392.                     strcpy(prev_token, cur_token);
  393.  
  394.                     /* check for membership in the tagging symbol club */
  395.                     if (ASMIsMember(ASM_sym, cur_token, &symbol_index)) {
  396.                         state = Symbol1;
  397.                     }
  398.                     else {
  399.  
  400.                         /* check if comment block */
  401.                         if (ASMIsMember(ASM_comment_block,
  402.                                         cur_token, &symbol_index)) {
  403.  
  404.                             /* get the next non white character, this makes
  405.                              * the assumption that the delimiter character is
  406.                              * on the same line as the comment symbol. If the
  407.                              * delimiter character is not on the current line
  408.                              * then parsing continues normally on the next
  409.                              * line. */
  410.                             while (IsWhite(*lptr)) {
  411.                                 lptr++;
  412.                             }
  413.  
  414.                             if (*lptr) {
  415.  
  416.                                 /* this is the delimiter character, store it
  417.                                  * and move lptr past it */
  418.                                 *cur_token = *lptr;
  419.                                 lptr++;
  420.  
  421.                                 /* move over comment block, remembering to
  422.                                  * update line info as we go */
  423.                                 while (*lptr != *cur_token) {
  424.  
  425.                                     /* get a new line if end of line */
  426.                                     if (!*lptr) {
  427.                                         if (!GetLine(infile, line,
  428.                                                      TOKEN_LINE_LENGTH)) {
  429.                                             *cur_token = *lptr;
  430.                                         }
  431.                                         else {
  432.                                             lptr = line;
  433.  
  434.                                             /* increment counters */
  435.                                             line_number++;
  436.  
  437.                                             /* char_number increments by
  438.                                              * length of previous line */
  439.                                             char_number += line_length + 1;
  440.  
  441.                                             /* line length */
  442.                                             line_length = strlen(line);
  443.                                         }
  444.                                     }
  445.                                     else {
  446.                                         lptr++;
  447.                                     }
  448.                                 }
  449.                             }
  450.  
  451.                             state = Discard;
  452.                         }
  453.                         else {
  454.  
  455.                             /* nothing special, parse the next symbol */
  456.                             state = Parse2;
  457.                         }
  458.                     }
  459.                 }
  460.                 break;
  461.  
  462.             case Parse2:        /* parsing for second *special* token */
  463.  
  464.                 /* save the previous position */
  465.                 prev_lptr = lptr;
  466.  
  467.                 /* get the next token */
  468.                 if (!ASM_get_token(&lptr, cur_token)) {
  469.  
  470.                     /* no token left, reset machine */
  471.                     state = Discard;
  472.                 }
  473.                 else {
  474.  
  475.                     if (ASMIsMember(ASM_sym, cur_token, &symbol_index)) {
  476.  
  477.                         /* found a major symbol */
  478.                         state = Symbol2;
  479.                     }
  480.                     else {
  481.  
  482.                         if (ASMIsMember(ASM_def, cur_token, &symbol_index)) {
  483.  
  484.                             /* found a defining token */
  485.                             state = Define;
  486.                         }
  487.                         else {
  488.                             state = Discard;
  489.                         }
  490.                     }
  491.                 }
  492.  
  493.                 break;
  494.  
  495.             case Symbol1:       /* next token, ignore if no token found */
  496.  
  497.                 /* get the next symbol and output it */
  498.                 if (ASM_get_token(&lptr, cur_token)) {
  499.  
  500.                     /* output if wanted */
  501.                     if (ASMSymbolWanted(flags, symbol_index)) {
  502.                         OutputTag(outfile, line, cur_token, infname,
  503.                                   line_number, char_number +
  504.                                   abs(lptr - line) -
  505.                                   strlen(cur_token),
  506.                                   flags);
  507.                     }
  508.                 }
  509.  
  510.                 /* reset machine */
  511.                 state = Discard;
  512.  
  513.                 break;
  514.  
  515.             case Symbol2:       /* previous token was the wanted symbol */
  516.  
  517.                 /* the previous token is the symbol of interest */
  518.                 /* output if wanted */
  519.                 if (ASMSymbolWanted(flags, symbol_index)) {
  520.                     OutputTag(outfile, line, prev_token, infname,
  521.                               line_number, char_number +
  522.                               abs(prev_lptr - line) -
  523.                               strlen(prev_token),
  524.                               flags);
  525.                 }
  526.  
  527.                 /* reset machine */
  528.                 state = Discard;
  529.  
  530.                 break;
  531.  
  532.             case Define:        /* previous token was the wanted symbol */
  533.  
  534.                 /* the previous token is the symbol of interest */
  535.                 /* output if wanted */
  536.                 if ((flags->ad && symbol_index != 1) ||
  537.                     (flags->al && symbol_index == 1)) {
  538.                     OutputTag(outfile, line, prev_token, infname,
  539.                               line_number, char_number +
  540.                               abs(prev_lptr - line) -
  541.                               strlen(prev_token),
  542.                               flags);
  543.                 }
  544.  
  545.                 /* reset machine */
  546.                 state = Discard;
  547.  
  548.                 break;
  549.  
  550.             case Exit:          /* clean it up */
  551.                 return;
  552.                 break;
  553.  
  554.             default:            /* not reached */
  555.                 break;
  556.         }
  557.     }
  558. }
  559.